home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Tools 2
/
Amiga Tools 2.iso
/
tools
/
mg
/
src.lzh
/
amiga
/
ttyio.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-05-23
|
29KB
|
1,218 lines
/*
* Name: MG 2a Amiga terminal window I/O, with all kinds o' trimmings.
* This module is 'way too big. Last Edit: 01-Dec-87
* mic@emx.cc.utexas.edu Created: 21-Apr-86 mic@emx.cc.utexas.edu
*/
#undef MANX
#undef LATTICE
#include "rexx.h"
#include "no_dir.h"
#include "compiler.h"
#include "change_font.h"
#include "v11.h"
#include "mouse.h"
#include "no_metakey.h"
#include "promptwait.h"
#include "nrow.h"
#include "ncol.h"
#include "init_cols.h"
#include "init_rows.h"
#include "do_menu.h"
#ifndef NO_METAKEY
#include "metabit.h"
#endif
#include "use_arp.h"
#ifdef USE_ARP
#include <arpfunctions.h>
#endif
/*
* Lots of includes.
*/
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/tasks.h>
#include <exec/ports.h>
#include <exec/io.h>
#include <devices/console.h>
#include <devices/inputevent.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <graphics/clip.h>
#include <graphics/view.h>
#include <graphics/rastport.h>
#include <graphics/layers.h>
#include <graphics/text.h>
#include <graphics/gfxbase.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#undef TRUE
#undef FALSE
#include "def.h" /* includes sysdef.h and ttydef.h */
#include "window.h"
#ifdef REXX
#include "key.h"
#endif
#ifdef CHANGE_FONT
#include <libraries/diskfont.h>
#endif
#ifdef LATTICE
#ifdef CHANGE_FONT
#include <proto/diskfont.h>
#endif
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <proto/console.h>
#else
#include <functions.h>
#endif
#ifdef ANSI
#include <string.h>
#include <stdlib.h>
#endif
#ifdef USE_ARP
struct ArpBase *ArpBase;
#endif
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
#ifndef NO_DIR
extern struct Task *FindTask();
static BPTR StartLock;
char WindowTitle[MAXPATH + 20], *MyDirName;
#ifndef MANX
extern BPTR DupLock(), CurrentDir();
#endif
#endif /* NO_DIR */
#ifdef DO_MENU
extern struct Menu *InitEmacsMenu();
#endif
#ifndef LATTICE
extern int Enable_Abort; /* Do NOT allow abort! */
#endif
/*
* External MG functions and variables
*/
extern char version[]; /* Version information */
extern int ttrow; /* Current cursor row */
extern int use_metakey; /* Do meta characters? */
/*
* My own, internal functions
*/
static VOID amigaclean PROTO((void));
static void setmaxima PROTO((void));
static struct Screen *wbscreen PROTO((void));
static void ttreopen PROTO((int resize));
static int handle_kbd PROTO((int timeout));
static int dispatch PROTO((struct IntuiMessage * msg));
static int nextkey PROTO((void));
static void qkey PROTO((short k));
#ifdef MOUSE
static void qmouse PROTO((short x, short y, unsigned short qual));
#endif
#ifdef DO_MENU
static void qmenu PROTO((unsigned short code));
#endif
#ifdef MANX
/* these are in localproto.h, but this is not included for MANX3.6 */
VOID ttclose();
VOID setttysize();
VOID syscleanup();
VOID ttflush();
VOID panic();
#endif
/*
* Library bases (used by glue libraries)
*/
#ifndef LATTICE
#ifdef CHANGE_FONT
struct DiskFontBase * DiskfontBase;
#endif
#endif
/*
* Intuition window and menu variables. MG gets used a lot, because it gets
* reconfigured on the fly for the amiga-set-font and toggle-border
* operations.
*/
#define WINDOWGADGETS (WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE)
#define WINDOWFLAGS (WINDOWGADGETS | ACTIVATE)
struct NewWindow MG = {
0, 0, /* start position */
0, 0, /* width, height (set by ttopen) */
0, 1, /* detail pen, block pen */
#ifdef DO_MENU
MENUPICK | /* If menu is used */
#endif
#ifdef MOUSE
MOUSEBUTTONS | /* If mouse is used */
#endif
INTUITICKS | RAWKEY |
CLOSEWINDOW | NEWSIZE, /* IDCMP flags */
0, /* window flags (set by ttopen) */
NULL, /* pointer to first user gadget */
NULL, /* pointer to user checkmark */
NULL, /* title (filled in later) */
NULL, /* pointer to screen (none) */
NULL, /* pointer to superbitmap */
220, 40, /* minimum size (small!) */
0, 0, /* maximum size (set by ttopen) */
WBENCHSCREEN /* screen in which to open */
};
static short borderless = TRUE; /* Flag for borderless window */
static short toggle_zooms = TRUE; /* Does toggling border zoom? */
static int last_top, last_left, last_height, last_width;
struct Window *EmW = NULL; /* Our window */
struct Screen *EmS = NULL; /* Our screen (usually WB) */
short toggling = FALSE; /* Prevent menu wiping */
#ifndef V11
struct Screen WBInfo; /* Info about the WB screen */
#endif
struct TextFont *EmFont = NULL; /* Our font (usually TOPAZ_xx) */
#ifdef DO_MENU
static struct Menu *EmacsMenu = NULL; /* Our menu */
#endif
#if 0
static ULONG class; /* Intuition event */
static USHORT code, /* information */
qualifier;
static APTR address;
static SHORT x, y;
#endif /* 0 */
static LONG intuitionMsgMask;/* Signal Mask */
/* * * * * * * * * * * * * console I/O * * * * * * * * * * * * * * * * */
#define CSI 0x9b /* Command Sequence Introducer */
#define NOBUF 512 /* About 1/4 screen */
#define NIBUF 256 /* Input buffer */
static KCHAR ibuf[NIBUF]; /* keyboard input buffer */
static int ibufo, nibuf; /* head, # of bytes in ibuf */
static LONG tickcount; /* # intuiticks since last char */
static struct MsgPort *conWritePort = NULL; /* I/O ports */
static struct IOStdReq *conWriteMsg = NULL; /* I/O messages */
struct Library *ConsoleDevice; /* used by RawKeyConvert */
static unsigned char outbuf[NOBUF + 7]; /* output buffer */
static unsigned char *obuf; /* first output char */
int nobuf; /* # of bytes in above */
int nrow; /* Terminal size, rows. */
int ncol; /* Terminal size, cols. */
/* * * * * * * * * functions to open/reopen the window * * * * * * * * * */
/*
* Open up the virtual terminal MG communicates with. Set up the window,
* console, and menu strip.
*/
ttopen()
{
#ifndef LATTICE
Enable_Abort = 0; /* Disable ^C */
#endif
/* Set the window size, set the flags and title, and open it */
setmaxima();
MG.Flags = WINDOWFLAGS;
MG.Flags |= borderless ? BORDERLESS : WINDOWSIZING;
#ifndef NO_DIR
MG.Title = (UBYTE *) WindowTitle;
#else
MG.Title = (UBYTE *) version;
#endif
if ((EmW = OpenWindow(&MG)) == NULL)
amigaclean();
SetFont(EmW->RPort, EmFont);
/*
* Once the window is created, get the Intuition signal bit, set up
* the menu, and tell the virtual terminal how big it is.
*/
setttysize();
intuitionMsgMask = 1L << EmW->UserPort->mp_SigBit;
#ifdef DO_MENU
if (toggling == FALSE)
EmacsMenu = InitEmacsMenu(EmW);
if (EmacsMenu == NULL)
amigaclean();
SetMenuStrip(EmW, EmacsMenu);
#endif
/*
* Attach a console device (purely for output now) to our window
*/
if ((conWritePort = CreatePort("Emacs.con.write", 0L)) == NULL)
amigaclean();
if ((conWriteMsg = CreateStdIO(conWritePort)) == NULL)
amigaclean();
if (OpenConsole(conWriteMsg, NULL, EmW) != 0)
amigaclean();
ConsoleDevice = (struct Library *) conWriteMsg->io_Device;
nibuf = ibufo = 0;
return (0);
}
/*
* Set up the initial state of the window. Opens up libraries, decides how
* big the initial window should be, and whether it should be borderless.
*/
VOID
sysinit()
{
#ifndef NO_DIR
long len;
BPTR MyDirLock;
#endif
GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 0L);
if (GfxBase == NULL) /* Graphics lib */
amigaclean();
IntuitionBase = (struct IntuitionBase *) /* Intuition */
OpenLibrary("intuition.library", 0L);
if (IntuitionBase == NULL)
amigaclean();
#ifdef USE_ARP
if (!(ArpBase = (struct ArpBase *) OpenLibrary("arp.library", 0L)))
panic("Compiled with USE_ARP, but arp.library not found");
#endif
#ifdef REXX
openrexx();
#endif
#ifndef NO_DIR
/*
* The following attempt to be clever assigns the external StartLock
* to the lock on the current directory, then switches our CurrentDir
* to a duplicate of that lock so we can restore the original lock on
* exit.
*/
strcpy(WindowTitle, version);
strcat(WindowTitle, ": ");
MyDirName = strchr(WindowTitle, '\0');
StartLock = ((struct Process *) FindTask(0L))->pr_CurrentDir;
(void) CurrentDir(MyDirLock = DupLock(StartLock));
len = PathName(MyDirLock, MyDirName, MAXPATH);
#endif /* NO_DIR */
#ifdef CHANGE_FONT
#ifndef LATTICE
DiskfontBase = (struct DiskFontBase *) OpenLibrary("diskfont.library", 0L);
#else
DiskfontBase = OpenLibrary("diskfont.library", 0L);
#endif
if (DiskfontBase == NULL)
amigaclean();
#endif
/* Get our screen and font, then figure out if we can go borderless */
if ((EmS = wbscreen()) == NULL)
amigaclean();
#ifdef CHANGE_FONT
EmFont = OpenDiskFont(EmS->Font);
#else
EmFont = OpenFont(EmS->Font);
#endif
if ((EmS->Width >= ((INIT_COLS * EmFont->tf_XSize) + LR_BORDER)) &&
(EmS->Height >= ((INIT_ROWS * EmFont->tf_YSize) + TB_BORDER)))
borderless = FALSE;
/*
* Set the size of the initial window and fake the last one
*/
last_width = MG.Width = EmS->Width;
last_height = MG.Height = EmS->Height;
last_left = MG.LeftEdge = 0;
last_top = MG.TopEdge = 0;
strcpy(outbuf, "\x9b" "0 p"); /* preload cursor off sequence */
obuf = outbuf + 4;
}
/*
* Make sure the window isn't bigger than NROW * NCOL, while accounting for
* borders & such. Since the window might not be at its largest right now,
* deadstop both the current width and the maxwidth.
*/
static VOID
setmaxima()
{
register int maxw, maxh;
MG.MaxWidth = EmS->Width;
MG.MaxHeight = EmS->Height;
maxw = NCOL * EmFont->tf_XSize + (borderless ? 0 : LR_BORDER);
maxh = NROW * EmFont->tf_YSize + (borderless ? TOP_OFFSET : TB_BORDER);
if (MG.MaxWidth > maxw)
MG.MaxWidth = maxw;
if (MG.Width > maxw)
MG.Width = maxw;
if (MG.MaxHeight > maxh)
MG.MaxHeight = maxh;
if (MG.Height > maxh)
MG.Height = maxh;
}
/*
* Return a pointer the workbench screen, using GetScreenData() to do things
* like a good citizen. Left the V11 code in as a reminder that what works
* is not always the _best_ way to do things. Thanks to Tom Rokicki for
* reminding me (mpk) this had to be done.
*/
static struct Screen
*
wbscreen()
{
#ifndef V11
return GetScreenData((char *) &WBInfo, (long) sizeof(WBInfo),
WBENCHSCREEN, NULL) ? &WBInfo : ((struct Screen *) NULL);
#else
register struct Screen *s;
Forbid();
for (s = IntuitionBase->FirstScreen; s; s = s->NextScreen)
if ((s->Flags & SCREENTYPE) == WBENCHSCREEN)
break;
Permit();
return (s);
#endif
}
/*
* Hide the window and open it up again. If resize is TRUE, they're being
* called as part of a resize operation, so assume that the NewWindow
* structure is set correctly. Otherwise, store the current window size and
* position in the NewWindow structure.
*
* These two functions are split so we can do things like ttreopen() and
* tticon() cleanly.
*/
VOID
tthide(resize)
int resize;
{
toggling = TRUE;
if (resize == FALSE) { /* if we're resizing, */
MG.LeftEdge = EmW->LeftEdge; /* use current window size */
MG.TopEdge = EmW->TopEdge;
MG.Width = EmW->Width;
MG.Height = EmW->Height;
}
ttclose(); /* reset to zero */
}
VOID
ttshow(resize)
int resize;
{
ttopen(); /* re-open tty window */
ttinit(); /* re-initalize tty */
sgarbf = TRUE; /* screen was trashed */
if (resize == TRUE)
nrow = ncol = -1; /* trash screen size */
refresh(FFARG, 1); /* and redraw it */
toggling = FALSE; /* Ok, done */
}
/*
* ttreopen() was split into the two functions above when tticon() was
* introduced.
*/
static VOID
ttreopen(resize)
int resize;
{
tthide(resize);
ttshow(resize);
}
/* * * * * * * * * * * * functions to close the window * * * * * * * * */
/*
* Close the virtual terminal. If toggling, don't release all the other
* resources we've allocated.
*/
VOID
ttclose()
{
ttflush();
if (conWriteMsg!=NULL) {
CloseDevice((struct IORequest *) conWriteMsg);
DeleteStdIO(conWriteMsg);
conWriteMsg = NULL;
}
if (conWritePort!=NULL) {
DeletePort(conWritePort);
conWritePort = NULL;
}
if (EmW!=NULL) {
#ifdef DO_MENU
ClearMenuStrip(EmW);
#endif
CloseWindow(EmW);
EmW=NULL;
}
#ifndef LATTICE
Enable_Abort = 1;
#endif
}
/*
* To explain the many paths out of mg:
*
* ttclose: Shuts down the window & associated IO devices. This gets called to
* go to a "quiescent" state - iconified, or waiting for rexx.
*
* syscleanup: Closes everything, in preperation for shutting down permanently.
*
* amigaclean: Calls the above two routines in order, then exits quietly Used
* when we're not up yet, and something fails to open.
*
* panic: Displays a message in the echo area, then does an amigaclean. Used to
* die in emergencies from an up state.
*/
/*
* Shut 'er down scotty, she's sucking mud! Usefull even when we're not all
* the way up yet.
*/
VOID
amigaclean()
{
ttclose();
syscleanup();
exit(20);
}
/*
* System dependent cleanup for the Amiga.
*/
VOID
syscleanup()
{
#ifdef REXX
closerexx();
#endif
#ifndef NO_DIR
UnLock(CurrentDir(StartLock)); /* restore startup directory */
#endif
if (conWriteMsg)
DeleteStdIO(conWriteMsg);
if (conWritePort)
DeletePort(conWritePort);
#ifdef DO_MENU
if (EmacsMenu)
DisposeMenus();
#endif
if (EmFont)
CloseFont(EmFont);
#ifdef CHANGE_FONT
if (DiskfontBase)
CloseLibrary((struct Library *) DiskfontBase);
#endif
if (IntuitionBase)
CloseLibrary((struct Library *) IntuitionBase);
if (GfxBase)
CloseLibrary((struct Library *) GfxBase);
#ifdef USE_ARP
if (ArpBase)
CloseLibrary((struct Library *) ArpBase);
#endif
}
/* * * * * * * * functions that diddle the window and reopen it * * * * * */
/*
* Toggle between a borderless window and a sizeable window. This lets you
* use the whole screen if you want. Bound to "amiga-toggle-border".
*/
togglewindow(f, n)
{
if ((borderless = !borderless) == TRUE) { /* *always* save last */
last_top = EmW->TopEdge; /* bordered window size */
last_left = EmW->LeftEdge;
last_width = EmW->Width;
last_height = EmW->Height;
}
if (toggle_zooms == FALSE) { /* just use current size */
ttreopen(FALSE);
return (TRUE);
}
/*
* zooming -- if borderless, go as big as possible. If bordered, set
* to last saved value of bordered window
*/
if (borderless) {
MG.LeftEdge = 0;
MG.TopEdge = 0;
MG.Width = MG.MaxWidth;
MG.Height = MG.MaxHeight;
} else {
MG.LeftEdge = last_left;
MG.TopEdge = last_top;
MG.Width = last_width;
MG.Height = last_height;
}
ttreopen(TRUE); /* open with new size */
return (TRUE);
}
/*
* Modify the action of "amiga-toggle-border", reporting outcome to user.
* Bound to "amiga-zoom-mode".
*/
togglezooms(f, n)
{
toggle_zooms = !toggle_zooms;
ewprintf("Toggling border %s",
toggle_zooms ? "expands window to screen size" :
"retains current window size");
return (TRUE);
}
#ifdef CHANGE_FONT
/*
* Select a different font for the MG window. This does not work very well
* with proportional fonts, so we ask the user to confirm before he uses one.
* It's available if you want to be able to use your own disk font (or Topaz
* 11 under 1.2) to edit with.
*/
setfont(f, n)
{
register int s, size;
register struct TextFont *newfont;
char fontname[80], fontpath[84], fontsize[3];
struct TextAttr ta;
/*
* If negative size, reset to default font
*/
if ((f & FFARG) && (n <= 0)) {
CloseFont(EmFont); /* return old font */
EmFont = OpenDiskFont(EmS->Font); /* screen's default */
ttreopen(TRUE); /* we changed fonts, so resize */
ewprintf("Now using default font");
return (TRUE);
}
if ((s = ereply("Font name: ", fontname, sizeof(fontname))) != TRUE)
return (s);
strcpy(fontpath, fontname);
strncat(fontpath, ".font", sizeof(fontpath)); /* make name */
/* Get font size */
if (f & FFARG)
size = n;
else {
if ((s = ereply("Font size: ",
fontsize, sizeof(fontsize))) != TRUE)
return (s);
size = atoi(fontsize);
}
/* Set up text attributes */
ta.ta_Name = (UBYTE *) fontpath;
ta.ta_YSize = size;
ta.ta_Style = FS_NORMAL;
ta.ta_Flags = 0;
/* Look for the font */
ewprintf("Looking for %s %d...", fontname, size);
if ((newfont = OpenDiskFont(&ta)) == NULL) {
ewprintf("Can't find %s %d!", fontname, size);
return (FALSE);
}
/* Found it! Check before using it */
if ((newfont->tf_YSize != size) &&
((s = eyesno("Size unavailable - use closest")) != TRUE)) {
CloseFont(newfont);
return (FALSE);
}
if ((newfont->tf_Flags & FPF_PROPORTIONAL) &&
(((s = eyesno("Use proportional font"))) != TRUE)) {
CloseFont(newfont);
return (FALSE);
}
/* Get rid of old font and reopen with the new one */
CloseFont(EmFont);
EmFont = newfont;
ttreopen(TRUE); /* Different font sizes means we may need to resize */
ewprintf("Now using font %s %d", fontname, EmFont->tf_YSize);
return (TRUE);
}
#endif
/* * * * * * * * * * * * * console output functions * * * * * * * * * * * * */
/*
* Write a single character to the screen. Buffered for speed, so ttflush()
* does all the work.
*/
VOID
#ifdef NO_PROTO
ttputc(c)
unsigned char c;
#else
ttputc PROTO((unsigned char c))
#endif
{
obuf[nobuf++] = c;
if (nobuf >= NOBUF)
ttflush();
}
/*
* Flush characters from the output buffer. If the # of characters is
* greater than a certain ad-hoc value, turn the cursor off while doing the
* write. To avoid extra writes, the output buffer has been preloaded with
* the cursor-off sequence. Outbuf is large enough to hold the extra 7
* characters.
*/
#define MIN_OFF 8
VOID
ttflush()
{
if (nobuf > 0) {
if (nobuf <= MIN_OFF) /* don't turn off for short writes */
ConWrite(conWriteMsg, obuf, nobuf);
else {
obuf[nobuf++] = '\x9b';
obuf[nobuf++] = ' ';
obuf[nobuf++] = 'p';
ConWrite(conWriteMsg, outbuf, nobuf + 4);
}
nobuf = 0;
}
}
/*
* The caller intends to output an escape sequence, but only flush the buffer
* if there's not enough room to hold the complete sequence. This avoids
* breaking up escape sequences when we turn the cursor off in ttflush(), at
* the expense of some extra function calls.
*/
VOID
ttnflush(n)
int n;
{
if ((nobuf + n) > NOBUF)
ttflush();
}
/* * * * * * * * * * * * * console input functions * * * * * * * * * * * * */
/*
* Read a character (really a KCHAR, > 8 bits), blocking till a character is
* put in the input buffer and can be returned.
*/
ttgetc()
{
return handle_kbd(FALSE);
}
/*
* Return TRUE if we've waited for 2 seconds and nothing has happened, else
* return false.
*/
ttwait()
{
return handle_kbd(TRUE);/* time out after 2 sec */
}
/*
* Common routine for handling character input, with and without timeout.
* Handle events until:
*
* 1) a character is put in the input buffer 2) if timeout == TRUE, PROMPTWAIT
* IntuiTicks have gone by
*
* If timeout == FALSE, the input character is returned and removed from the
* input buffer.
*
* If timeout == TRUE, returns TRUE if the read timed out, else FALSE. Leaves
* any character typed in the input buffer.
*/
static
handle_kbd(timeout)
register int timeout;
{
register struct IntuiMessage *message; /* IDCMP message */
register LONG wakeupmask; /* which signals? */
register int charfound; /* got a character yet? */
#ifdef REXX
struct key savekey;/* Save current keystrokes */
extern struct MsgPort *rexxport; /* Bit to check for Rexx msgs */
register int rexxbit = 1l << rexxport->mp_SigBit;
#endif
tickcount = 0; /* *always* zero the count */
if (nibuf) /* any chars? return if so */
return timeout ? FALSE : nextkey();
charfound = FALSE; /* nope -- have to wait */
do {
wakeupmask = Wait(intuitionMsgMask
#ifdef REXX
| rexxbit
#endif
);
#ifdef REXX
/* Now handle any rexx messages if we need them */
if (wakeupmask & rexxbit) {
savekey = key;
disprexx(rexxport);
update();
key = savekey;
}
#endif
/* Handle Intuiticks specially for speed */
while (message = (struct IntuiMessage *) GetMsg(EmW->UserPort))
if (message->Class == INTUITICKS) {
tickcount++;
ReplyMsg((struct Message *) message);
} else if (dispatch(message) == TRUE)
charfound = TRUE;
/*
* time out if enough ticks have gone by without any keyboard
* input. We do this *after* all the events in the current
* list have been dispatched.
*/
if (timeout && (tickcount > PROMPTWAIT))
break;
} while (charfound == FALSE);
/*
* If called by ttwait(), return FALSE if a character was found. Else
* return the next character in the input buffer
*/
return timeout ? (!charfound) : nextkey();
}
/*
* Handle the events we handle... The result returned indicates if we've put
* a character in the input buffer.
*/
#ifndef NO_METAKEY
#define IEQUALIFIER_ALT (IEQUALIFIER_RALT | IEQUALIFIER_LALT)
#endif
static
dispatch(msg)
register struct IntuiMessage *msg;
{
#ifdef DO_MENU
register struct MenuItem *item;
#endif
register int txheight, txwidth;
register struct RastPort *rp;
int dx, dy, fgpen, drmode;
static struct InputEvent FakedEvent = {NULL, IECLASS_RAWKEY, 0, 0, 0};
#ifndef NO_METAKEY
unsigned char altbuf[64];
int altlen;
#endif
unsigned char keybuf[64];
int keylen, i;
#ifndef V11
APTR deadcodes;
#endif
ULONG class;
USHORT code,
qualifier;
APTR address;
SHORT x, y;
class = msg->Class; /* grab the info before we */
code = msg->Code; /* reply to the message */
qualifier = msg->Qualifier;
address = msg->IAddress;
x = msg->MouseX;
y = msg->MouseY;
#ifndef V11
if (class == RAWKEY) /* get dead key info */
deadcodes = (APTR) * address;
#endif
ReplyMsg((struct Message *) msg); /* return it to Intuition */
switch (class) { /* see what the fuss is about */
case RAWKEY:
FakedEvent.ie_Code = code;
FakedEvent.ie_Qualifier = qualifier;
#ifndef V11
FakedEvent.ie_EventAddress = deadcodes;
#endif
keylen = (int) RawKeyConvert(&FakedEvent,
keybuf, (LONG) sizeof(keybuf), NULL);
#ifndef NO_METAKEY
/*
* Special mapping for ALT-ed keys. The intent is to allow
* extended ASCII characters that are generated without the
* ALT key to pass unscathed through getkbd(). However, if
* METABIT is 0x80 & use_metaky is on, they will get changed
* by getkey(). Hence, Amiga mg should be compiled with
* METABIT being 0x80.
*/
if ((qualifier & IEQUALIFIER_ALT) && use_metakey) {
FakedEvent.ie_Qualifier &= ~IEQUALIFIER_ALT;
altlen = (int) RawKeyConvert(&FakedEvent, altbuf,
(LONG) sizeof(altbuf), NULL);
if (altlen >= 1)
qkey((KCHAR) (METABIT | altbuf[0]));
for (i = 1; i < altlen; i++)
qkey((KCHAR) altbuf[i]);
return (altlen > 0) ? TRUE : FALSE;
}
#endif
/* non-ALTed key */
for (i = 0; i < keylen; i++)
qkey((KCHAR) keybuf[i]);
return (keylen > 0) ? TRUE : FALSE;
break;
#ifdef DO_MENU
case MENUPICK:
if (code == MENUNULL)
return (FALSE);
while (code != MENUNULL) { /* handle multiple selection */
qmenu(code);
item = ItemAddress(EmacsMenu, (LONG) code);
code = item->NextSelect;
}
return (TRUE); /* puts KMENU in event queue */
break;
#endif
#ifdef MOUSE
case MOUSEBUTTONS: /* fake the mouse key */
if (code != SELECTDOWN) /* ignore SELECTUP */
return (FALSE);
qmouse(x, y, qualifier);
return (TRUE);
break;
#endif
case NEWSIZE:
/*
* Sometimes when you resize the window to make it smaller,
* garbage is left at the right and bottom sides of the
* window. This code is devoted to (somehow) getting rid of
* this garbage. Any suggestions?
*/
rp = EmW->RPort;
fgpen = rp->FgPen; /* save params */
drmode = rp->DrawMode;
SetDrMd(rp, (LONG) JAM1);
SetAPen(rp, (LONG) EmW->RPort->BgPen);
/*
* Check the bottom of the window
*/
txheight = EmW->Height - EmW->BorderTop - EmW->BorderBottom;
if (dy = (txheight % FontHeight(EmW)))
RectFill(rp,
(LONG) EmW->BorderLeft,
(LONG) EmW->BorderTop + txheight - dy - 1,
(LONG) (EmW->Width - 1) - EmW->BorderRight,
(LONG) (EmW->Height - 1) - EmW->BorderBottom);
/*
* Check the right side
*/
txwidth = EmW->Width - EmW->BorderLeft - EmW->BorderRight;
if (dx = txwidth % FontWidth(EmW))
RectFill(rp,
(LONG) EmW->BorderLeft + txwidth - dx - 1,
(LONG) EmW->BorderTop,
(LONG) (EmW->Width - 1) - EmW->BorderRight,
(LONG) (EmW->Height - 1) - EmW->BorderBottom);
SetDrMd(rp, (LONG) drmode);
SetAPen(rp, (LONG) fgpen); /* restore colors */
/* Tell the console device to resize itself */
ttputc(CSI);
ttputc('t');
ttputc(CSI);
ttputc('u');
ttflush();
/*
* Signal the editor that a new size has occurred. I may
* break down and do this asynchronously...
*/
qkey(KRESIZE);
return (TRUE); /* we done (finally) */
break;
case CLOSEWINDOW:
/* Calling quit() directly is not a guaranteed win. */
quit(FFRAND, 1);
return (FALSE);
break;
default:
panic("HandleMsg: unknown event!!!");
break;
}
return (FALSE);
}
/*
* Return the current size of the virtual terminal in nrow and ncol, making
* sure we don't go beyond the size of the internal video array. Assumes the
* current font is monospaced.
*/
VOID
setttysize()
{
nrow = (EmW->Height - TOP_OFFSET
- EmW->BorderBottom) / FontHeight(EmW);
ncol = (EmW->Width - EmW->BorderLeft
- EmW->BorderRight) / FontWidth(EmW);
if (nrow < 1)
nrow = 1;
if (nrow > NROW)
nrow = NROW;
if (ncol < 1)
ncol = 1;
if (ncol > NCOL)
ncol = NCOL;
}
/*
* Exit as soon as possible, after displaying the message.
*/
VOID
panic(s)
char *s;
{
ewprintf(s); /* put message at bottom */
Delay((ULONG) 90); /* wait 1.5 seconds */
amigaclean(); /* Go Way */
}
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Event
* buffer management * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
/*
* Return next key in the input buffer, if any available. Returns -1 if not.
*/
static int
nextkey()
{
register KCHAR k;
if (nibuf <= 0) { /* shouldn't happen, but could... */
nibuf = 0;
return -1;
} else {
k = ibuf[ibufo++];
nibuf--;
ibufo %= NIBUF;
return (int) k;
}
}
/*
* Return true if there are some characters available in the input buffer.
*/
typeahead()
{
return (nibuf > 0);
}
/*
* Add a key to the input queue
*/
static VOID
qkey(k)
KCHAR k;
{
if (nibuf < NIBUF)
ibuf[(ibufo + nibuf++) % NIBUF] = k;
}
#ifdef MOUSE
/*
* Add a mouse event to the input queue, calculating the row and column value
* from the current height and width of the window's font.
*/
static VOID
qmouse(x, y, qual)
SHORT x, y;
USHORT qual;
{
register int myqual = MQ_NOQUAL;
register int row, col;
register struct window *wp;
/* get row, column */
col = (x - EmW->BorderLeft) / FontWidth(EmW);
row = (y - TOP_OFFSET) / FontHeight(EmW);
/* find out which kind of window was clicked in */
for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
if ((row >= wp->w_toprow) &&
(row <= (wp->w_toprow + wp->w_ntrows)))
break;
if (wp == NULL)
myqual |= MQ_ECHO;
else if (row == (wp->w_toprow + wp->w_ntrows))
myqual |= MQ_MODE;
else
myqual |= MQ_WINDOW;
/* figure out qualifiers */
if (qual & IEQUALIFIER_CONTROL)
myqual |= MQ_CTRL;
if (qual & (IEQUALIFIER_LSHIFT | IEQUALIFIER_LSHIFT))
myqual |= MQ_SHIFT;
if (qual & (IEQUALIFIER_LALT | IEQUALIFIER_RALT))
myqual |= MQ_ALT;
/*
* Queue up the whole mess. If user didn't click in the echo line,
* transmit the x, y values to the mouse function
*/
qkey((KCHAR) (KW___MOUSE + myqual));
if (MQ_WHERE(myqual) != MQ_ECHO) {
qkey((KCHAR) (M_X_ZERO + col));
qkey((KCHAR) (M_Y_ZERO + row));
}
}
#endif
#ifdef DO_MENU
/*
* Add a menu event to the queue.
*/
static VOID
qmenu(code)
USHORT code;
{
qkey(KMENU); /* menu key sequence */
qkey((KCHAR) (MENUNUM(code) + MN_OFFSET));
qkey((KCHAR) (ITEMNUM(code) + MN_OFFSET));
qkey((KCHAR) (SUBNUM(code) + MN_OFFSET));
}
#endif
void
sleep(n)
int n;
{
if (n > 0)
Delay((long) n * TICKS_PER_SECOND);
}
#ifdef MANX
/* Define some Manx specific functions */
/*
* the only realloc function for MANX 3.6 is in heapmem.o which allocates
* storage from a buffer that is fixed in size (read SUCKS ROCKS)!, so
* here is a function that is compatible with the documentation for realloc
* that is in MANX 5.0.
*/
void *
realloc(blk, newlen)
char *blk;
int newlen;
{
char *nblk;
if (newlen == 0) {
free(blk);
blk=(char *)0;
return(blk);
} else {
nblk = malloc(newlen);
if (blk != (char *)0) {
movmem(blk, nblk, newlen);
free(blk);
}
blk=nblk;
}
return(blk);
}
/*
* Again, MANX doesn't seem to have real useful and regular functions
* in the 3.6 release. Here is a memcmp function for MANX3.6.
*/
int
m_memcmp(s1,s2,l)
char *s1, *s2;
int l;
{
while (l--) {
if (*s1==*s2)
s1++,s2++;
else {
if (*s1<*s2)
return -1;
else
return 1;
}
}
return(0);
}
#endif